using System;
using System.Xml;
using System.Text;
using System.Globalization;


namespace Waymex.Gps
{
	/// <summary>
	/// Collection of TrackPoint objects.
	/// </summary>

	public class TrackpointCollection : System.Collections.IEnumerable
	{		
		private System.Collections.ArrayList mcTrackpoints;

		private int m_hashCode = -1;

		private const string XML_ROOT = "gpstrackpoints";
		private const string  XML_TRACKPOINT = "gpstrackpoint";
		/// <summary>
		/// Constructor.
		/// </summary>
		public TrackpointCollection() : base()
		{
			mcTrackpoints = new System.Collections.ArrayList();
		}
		/// <summary>
		/// Returns an Enumerator for the Collection.
		/// </summary>
		public System.Collections.IEnumerator GetEnumerator()
		{
			return mcTrackpoints.GetEnumerator();
		}
		/// <summary>
		/// Allows a Trackpoint Object to be added to the collection. 
		/// </summary>
		public void Add(Trackpoint trackPoint)
		{
			try
			{
				mcTrackpoints.Add(trackPoint);
			}
		
			catch (Exception e)
			{
                throw new InvalidDataException(e.Message, e);
			}
		
		}
		/// <summary>
		/// Returns the number of Trackpoint objects in the collection. 
		/// </summary>
		public int Count
		{
			get
			{
				try
				{
					return mcTrackpoints.Count;
				}
	
				catch (Exception e)
				{
                    throw new InvalidDataException(e.Message, e);
				}

			}
		}
		/// <summary>
		/// Can be used to refer to a member of the collection by ordinal reference. 
		/// This Property is the default indexer property in C#.
		/// </summary>
		public Trackpoint this[int index]
		{
			get
			
			{
				try
				{
					return (Trackpoint)mcTrackpoints[index];
				}
				catch (Exception e)
				{
                    throw new InvalidDataException(e.Message, e);
				}
			}
		}
        /// <summary>
        /// Returns an XML representation of the object.
        /// </summary>
        public string ToXml()
        {
            return ToXml(String.Empty);
        }
        /// <summary>
        /// Returns an XML representation of the object.
        /// This overloaded method accepts an xslt filename which can be used to ransform the xml.
        /// </summary>
        public string ToXml(string xsltFilename)
		{
			StringBuilder strbldXML = new StringBuilder("");
            String xml = String.Empty;

			try
			{
				strbldXML.Append ("<");
				strbldXML.Append (XML_ROOT);
				strbldXML.Append (">");

				foreach(Trackpoint objTrackpoint in mcTrackpoints)
				{
					strbldXML.Append(objTrackpoint.ToXml());
				}

				strbldXML.Append ("</");
				strbldXML.Append (XML_ROOT);
                strbldXML.Append (">");

                //transform if required
                xml = strbldXML.ToString();

                if (xsltFilename.Length > 0)
                {
                    xml = Waymex.Xml.Transform.XsltTransform(xml, xsltFilename);
                }            

			}
            catch (NullReferenceException e)
            { 
				throw new XmlException(e.Message, e);

			}
			return xml;
		}

		/// <summary>
		/// This method populates the object from XML.
		/// </summary>
        public void XmlLoad(string xml)
		{

			XmlDocument objDOM = new XmlDocument();

			try
			{
                objDOM.LoadXml(xml);

				if(objDOM.FirstChild.Name == XML_ROOT)
				{
					foreach(XmlNode objNode in objDOM.FirstChild.ChildNodes)
					{
						try
						{
							switch(objNode.Name)
							{
								case XML_TRACKPOINT:

									Trackpoint objTrackpoint = new Trackpoint();
									objTrackpoint.XmlLoad(objNode.OuterXml);
									mcTrackpoints.Add(objTrackpoint);
									break;
							
							}
						}
                        catch (NullReferenceException ex)
						{
						}
					}
				}	
			}
            catch (NullReferenceException e)
            {
				throw new XmlException(e.Message, e);
			}
		}
		/// <summary>
		/// This method returns a System.Data.Dataset populated with the contents of the TrackpointCollection object.
		/// The dataset includes one table called 'Trackpoints'.
		/// </summary>
		public System.Data.DataSet ToDataSet()
		{
			//constants for the dataset
			const string DS_TRACKPOINTS = "Trackpoints";

//			//constants for the tracklog table
//			const string DS_TABLE_TRACKLOGS = "Tracklogs";
//			const string DS_FIELD_TRACKLOG_ID = "Route ID"; //PK
//			const string DS_FIELD_TRACKLOG_ID_TYPE = "System.Int32";
//			const string DS_FIELD_TRACKLOG_COLOUR = "Colour";
//			const string DS_FIELD_TRACKLOG_COLOUR_TYPE = "System.Int16";
//			const string DS_FIELD_TRACKLOG_DISPLAY = "Display";
//			const string DS_FIELD_TRACKLOG_DISPLAY_TYPE = "System.Boolean";
//			const string DS_FIELD_TRACKLOG_INDEX = "Index";
//			const string DS_FIELD_TRACKLOG_INDEX_TYPE = "System.Int32";
//			const string DS_FIELD_TRACKLOG_IDENTIFIER = "Identifier";
//			const string DS_FIELD_TRACKLOG_IDENTIFIER_TYPE = "System.String";
 
			//constants for the trackpoints table
			const string DS_TABLE_TRACKPOINTS = "Trackpoints";
			const string DS_FIELD_TRACKPOINT_LATITUDE = "Latitude";
			const string DS_FIELD_TRACKPOINT_LATITUDE_TYPE = "System.Double";
			const string DS_FIELD_TRACKPOINT_LONGITUDE = "Longitude";
			const string DS_FIELD_TRACKPOINT_LONGITUDE_TYPE = "System.Double";
			const string DS_FIELD_TRACKPOINT_NEW_TRACK = "New Track";
			const string DS_FIELD_TRACKPOINT_NEW_TRACK_TYPE = "System.Boolean";
			const string DS_FIELD_TRACKPOINT_TIME = "Time";
			const string DS_FIELD_TRACKPOINT_TIME_TYPE = "System.Int32";
			const string DS_FIELD_TRACKPOINT_ALTITUDE = "Altitude";
			const string DS_FIELD_TRACKPOINT_ALTITUDE_TYPE = "System.Single";
			const string DS_FIELD_TRACKPOINT_DEPTH = "Depth";
			const string DS_FIELD_TRACKPOINT_DEPTH_TYPE = "System.Single";
			const string DS_FIELD_TRACKPOINT_TEMPERATURE = "Temperature";
			const string DS_FIELD_TRACKPOINT_TEMPERATURE_TYPE = "System.Single";
			const string DS_FIELD_TRACKPOINT_DATETIME_OF_FIX = "Fix Date and Time";
			const string DS_FIELD_TRACKPOINT_DATETIME_OF_FIX_TYPE = "System.DateTime";


			//create a new data set
			System.Data.DataSet ds = new System.Data.DataSet(DS_TRACKPOINTS);
            ds.Locale = CultureInfo.InvariantCulture;
		
			//create the routes and waypoints table			
//			System.Data.DataTable dtTL = new System.Data.DataTable (DS_TABLE_TRACKLOGS);
			System.Data.DataTable dtTP = new System.Data.DataTable(DS_TABLE_TRACKPOINTS);
            dtTP.Locale = CultureInfo.InvariantCulture;
			
//			//add the columns to the routes table
//			dtTL.Columns.Add(DS_FIELD_TRACKLOG_ID, Type.GetType(DS_FIELD_TRACKLOG_ID_TYPE));
//			dtTL.Columns.Add(DS_FIELD_TRACKLOG_COLOUR, Type.GetType(DS_FIELD_TRACKLOG_COLOUR_TYPE));
//			dtTL.Columns.Add(DS_FIELD_TRACKLOG_DISPLAY, Type.GetType(DS_FIELD_TRACKLOG_DISPLAY_TYPE));
//			dtTL.Columns.Add(DS_FIELD_TRACKLOG_INDEX, Type.GetType(DS_FIELD_TRACKLOG_INDEX_TYPE));
//			dtTL.Columns.Add(DS_FIELD_TRACKLOG_IDENTIFIER, Type.GetType(DS_FIELD_TRACKLOG_IDENTIFIER_TYPE));

			//add the columns to the trackpoints table
//			dtTP.Columns.Add(DS_FIELD_TRACKLOG_ID, Type.GetType(DS_FIELD_TRACKLOG_ID_TYPE));
			dtTP.Columns.Add(DS_FIELD_TRACKPOINT_LATITUDE, Type.GetType(DS_FIELD_TRACKPOINT_LATITUDE_TYPE));
			dtTP.Columns.Add(DS_FIELD_TRACKPOINT_LONGITUDE, Type.GetType(DS_FIELD_TRACKPOINT_LONGITUDE_TYPE));
			dtTP.Columns.Add(DS_FIELD_TRACKPOINT_NEW_TRACK , Type.GetType(DS_FIELD_TRACKPOINT_NEW_TRACK_TYPE));
			dtTP.Columns.Add(DS_FIELD_TRACKPOINT_TIME, Type.GetType(DS_FIELD_TRACKPOINT_TIME_TYPE));
			dtTP.Columns.Add(DS_FIELD_TRACKPOINT_ALTITUDE, Type.GetType(DS_FIELD_TRACKPOINT_ALTITUDE_TYPE));
			dtTP.Columns.Add(DS_FIELD_TRACKPOINT_DEPTH, Type.GetType(DS_FIELD_TRACKPOINT_DEPTH_TYPE));
			dtTP.Columns.Add(DS_FIELD_TRACKPOINT_TEMPERATURE, Type.GetType(DS_FIELD_TRACKPOINT_TEMPERATURE_TYPE));
			dtTP.Columns.Add(DS_FIELD_TRACKPOINT_DATETIME_OF_FIX, Type.GetType(DS_FIELD_TRACKPOINT_DATETIME_OF_FIX_TYPE));

//			//add the data
//			int intTrackLogID = 0;
//			foreach(Tracklog objTrackLog in mcTrackLogs)
//			{
//				 
//				intTrackLogID++;
//				object[] objRow = new object[5];
//				objRow[0] = intTrackLogID;
//				objRow[1] = objTrackLog.Colour;
//				objRow[2] = objTrackLog.Display;
//				objRow[3] = objTrackLog.Index;
//				objRow[4] = objTrackLog.Identifier;
//				dtTL.Rows.Add(objRow);

	
				foreach(Trackpoint objTrackpoint in mcTrackpoints)
				{
					object[] objRow = new object[8];
					objRow[0] = objTrackpoint.Latitude;
					objRow[1] = objTrackpoint.Longitude;
					objRow[2] = objTrackpoint.NewTrack;
					objRow[3] = objTrackpoint.Time;
					objRow[4] = objTrackpoint.Altitude;
					objRow[5] = objTrackpoint.Depth;
					objRow[6] = objTrackpoint.Temperature;
					objRow[7] = objTrackpoint.FixDateTime;
					dtTP.Rows.Add(objRow);
				}
			
			//tables populated so add the tables to the dataset
//			ds.Tables.Add(dtTL);
			ds.Tables.Add(dtTP);

//			//tables now populated so add the relationship
//			System.Data.DataColumn parentCol = null;
//			System.Data.DataColumn childCol = null;
//
//			parentCol = ds.Tables[DS_TABLE_TRACKLOGS].Columns[DS_FIELD_TRACKLOG_ID];
//			childCol = ds.Tables[DS_TABLE_TRACKPOINTS].Columns[DS_FIELD_TRACKLOG_ID];
//
//			System.Data.DataRelation relTracklogTrackpoint = new System.Data.DataRelation(DS_RELATION_TRACKLOG_TRACKPOINT, parentCol, childCol);
//			ds.Relations.Add(relTracklogTrackpoint);

			return ds;
		}
        /// <summary>
        /// Overridden method. Returns true of the values of each
        /// of the properties are equal in value.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns>boolean</returns>
        public override bool Equals(object obj)
		{
			try
			{
				TrackpointCollection objTrackpoints = null;

				//check the type first
				if(obj.GetType() != this.GetType() )
					return false;

				//type ok so cast to trackpoints
				objTrackpoints = (TrackpointCollection)obj;

				//if the number of trackpoints in each collection is different then exit
				int w1Count = mcTrackpoints.Count;
				int w2Count = objTrackpoints.Count;
				if(w1Count != w2Count)
					return false;

				//both with the same number of elements so check each one in turn
				for( int index = 0; index < w1Count; index++ )
				{
					if( !objTrackpoints[index].Equals(mcTrackpoints[index], true) )
						return false;
				}
			}
			catch
			{
				throw;
			}
			finally
			{}

			//if we got here then they must match
			return true;
		}
        /// <summary>
        /// Overridden function. Retrieves a value that indicates the hash code value for the object.
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
		{
			//this value will be used for the overriden GetHashCode function and should
			//ensure that two object that are the same return the same Hash Code.
			//the hash code has to be imutable to is stored in a member variable.
			if( m_hashCode <= 0 )
				m_hashCode = this.ToXml().GetHashCode();
	
			return m_hashCode;
		}

	}
}
